package keter.ksf.main;

import com.google.common.collect.Lists;
import com.google.common.io.Files;
import com.jfinal.kit.PathKit;
import com.jfinal.kit.PropKit;
import keter.framework.util.IOUtil;
import keter.framework.util.PathUtil;
import keter.ksf.model.CellData;
import keter.ksf.model.Drink;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import keter.ksf.model.Mapping;
import keter.ksf.model.RangeDate;
import keter.ksf.util.MappingUtil;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;

/**
 * Created by gu on 2017/3/1.
 */
public class KsfApp {

    private static final Logger logger = LoggerFactory.getLogger(KsfApp.class);
    /*输入文件目录*/
    static String inputFolder;
    static XSSFWorkbook template;
    static int colBegin;
    static int rowNameCol;
    static int rowBegin;
    static int rowEnd;
    static File mappingFile;

    private static Mapping kwm;
    private static Mapping yys;
    private static Mapping kjkm;

    public KsfApp(){
        String extconfig = PathUtil.getJarPath()+"/config.properties";
        logger.info("尝试使用jar目录配置文件 {} 初始化应用...",extconfig);
        if(IOUtil.existsFile(extconfig)){
            init(extconfig);
        }
        else {
            logger.info("使用jar内部配置文件初始化...");
            init(PathKit.getRootClassPath()+"/config.properties");
        }
    }

    static void init(String config)  {
        PropKit.use(new File(config));
        inputFolder = PropKit.get("inputFolder");
        mappingFile = new File(PropKit.get("mappingFile"));
        rowNameCol = PropKit.getInt("rowNameCol")-1;
        rowBegin = PropKit.getInt("rowBegin")-1;
        rowEnd = PropKit.getInt("rowEnd")-1;
        colBegin = PropKit.getInt("colBegin")-1;
        try {
            template = new XSSFWorkbook(new FileInputStream(new File(PropKit.get("templateFile"))));
            kwm = MappingUtil.getMapping(mappingFile,0);
            yys = MappingUtil.getMapping(mappingFile,1);
            kjkm = MappingUtil.getMapping(mappingFile,2);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 读取目录下的全部文件，转换成Drink对象列表
     * @param folder
     * @return
     * @throws IOException
     */
    public  List<Drink> getDrinkList(String folder) throws IOException {
        File[] files = IOUtil.getFilesInCurrentPath(folder);
        List<Drink> drinkList = Lists.newArrayList();
        for (int i = 0; i < files.length; i++) {
            Drink drink = getDrinkFromFile(files[i]);
            drinkList.add(drink);
        }
        return drinkList;
    }

    public  List<Drink> getDrinkList() throws IOException {
        return getDrinkList(inputFolder);
    }

    /**
     * 同步模型：将Drink数据处理后所有结果全部更新到一个模板文件
     * @param drink
     * @throws IOException
     */
    public void makeResult(Drink drink) throws IOException {
        makeResult(drink,template);
    }

    /**
     * 异步模型：将Drink数据处理后更新到指定的模板文件
     * @param drink
     * @param template
     * @throws IOException
     */
    public void makeResult(Drink drink,XSSFWorkbook template) throws IOException {
        logger.info("处理：{}", drink.getFileName());
        for (XSSFSheet dataSheet : (List<XSSFSheet>) drink.get("sheetList")) {
//            logger.info("dataSheet:{}",dataSheet.getSheetName());
            //12个月
            for (int i = 1; i <= 12; i++) {
                XSSFSheet outSheet = template.getSheetAt(i);
//                logger.info("输出sheetName:{}",outSheet.getSheetName());
                RangeDate rangeData = getRangeData(dataSheet);
                List<CellData> cells =  rangeData.get(String.valueOf(i));
                int rowBegin = outSheet.getLastRowNum()+1;
                for (CellData cell : cells) {
                    XSSFRow row = outSheet.createRow(rowBegin);
                    //公司代码
                    row.createCell(1).setCellValue("SYP");
                    row.createCell(2).setCellValue("康师傅沈阳饮品有限公司");
                    row.createCell(3).setCellValue(LocalDateTime.now().getYear());
                    row.createCell(4).setCellValue(outSheet.getSheetName());//月份
                    row.createCell(5).setCellValue(kwm.getFirstValue(drink.getFileName()));//口味码[mapping]
                    row.createCell(6).setCellValue(kwm.getSecondValue(drink.getFileName()));//描述[mapping]
                    row.createCell(7).setCellValue(yys.getFirstValue(dataSheet.getSheetName()));//营业所编码[mapping]
                    row.createCell(8).setCellValue(yys.getSecondValue(dataSheet.getSheetName()));//营业所描述[mapping]
                    row.createCell(9).setCellValue(kjkm.getFirstValue(cell.getRowName()));//会计科目编码[mapping]
                    row.createCell(10).setCellValue(kjkm.getSecondValue(cell.getRowName()));//会计科目描述[mapping]
                    row.createCell(11).setCellValue(cell.getValue());
                    ++rowBegin;
                }
            }
        }
    }

    public static void writeFile() throws IOException {
        FileOutputStream fileOut = new FileOutputStream(PropKit.get("resultFile"));
        template.write(fileOut);
        logger.info("成果物[{}]写入完成！",PropKit.get("resultFile"));
        fileOut.close();
    }

    public static void writeFile(FileOutputStream fileOut, XSSFWorkbook template) throws IOException {
        template.write(fileOut);
        fileOut.close();
    }

    public Drink getDrinkFromFile(File f) throws IOException {
        XSSFWorkbook wb = new XSSFWorkbook(new FileInputStream(f));
        Drink drink = new Drink();
        drink.put("fileName", Files.getNameWithoutExtension(f.getAbsolutePath()));
        drink.put("wb",wb);
        logger.info("loading {} done!", drink.getFileName());
        List<XSSFSheet> stList = Lists.newArrayList();
        //跳过Sheet0(辽北)
        for (int i = 2; i < wb.getNumberOfSheets() ; i++) {
            stList.add(wb.getSheetAt(i));
        }
        drink.put("sheetList",stList);
        return drink;
    }

    /**
     * 从sheet页获取多列(1~12)数据
     * @param sheet
     * @return
     */
    public RangeDate getRangeData(XSSFSheet sheet) {
        RangeDate rangeDate = new RangeDate();
        int monthBegin = 1;//使用1~12月建立rangeDate映射关系
        for (int i = colBegin; i < colBegin+12; i++) {
            rangeDate.put(String.valueOf(monthBegin), getDataOfCol(sheet,i));
            ++monthBegin;
        }
        return rangeDate;
    }

    /**
     * 从sheet页获取单列数据
     * @param sheet
     * @param col
     * @return
     */
    private List<CellData> getDataOfCol(XSSFSheet sheet, int col){
        List<CellData> values = Lists.newArrayList();
        for (int i = rowBegin; i <= rowEnd; i++) {
//            logger.info("row:{},col:{}",i+1,colBegin-indent);
            String cellRowName = sheet.getRow(i).getCell(rowNameCol).getStringCellValue();
            //跳过“小计”行
            if(cellRowName.contains("小计")){
                continue;
            }
            //处理多行同时出现的“其他”
            if(cellRowName.equals("其他")){
                //根据出现行数拼接内容
                if(i==37) {//A1户外
                    cellRowName = "户外" + cellRowName;
                }
                else if(i==48) {//A1其他
                    cellRowName = "其他" + cellRowName;
                }
                else if(i==64) {//CP其他
                    cellRowName = "CP" + cellRowName;
                }
            }
            double d;
            try {
                d = sheet.getRow(i).getCell(col).getNumericCellValue() * 1000;
//                logger.info("rowName:{},value:{}",cellRowName,d);
            }
            catch (Exception e){
                logger.info("数字解析异常-sheet:{},row:{},col:{}",sheet.getSheetName(),i,col);
                d=0;
            }
            BigDecimal bg = new BigDecimal(d);
            CellData cd = new CellData();
            cd.put("rowName", cellRowName);
            cd.put("value",bg.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue());
            values.add(cd);
        }
        return values;
    }

    public void bankai() throws IOException {
        List<Drink> drinkList = getDrinkList(inputFolder);
        for (Drink drink : drinkList) {
            makeResult(drink);
        }
        writeFile();
    }
}